home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d18
/
totdoc.arc
/
CHAPT3.TXT
< prev
next >
Wrap
Text File
|
1991-02-10
|
49KB
|
1,059 lines
Toolkit Basics
"No, what I said was 'No new taxis'" Georgio Bush, 1990
An Object Primer
Let's talk cars. We all know that you don't need to be a combustion
mechanic to drive a car (that's a veeehickle if you're from Texas), but
most good drivers know a few basic principles about how a car works.
The same philosophy is true for object oriented programming: you don't
need to be an OOP guru to use the Toolkit but a little understanding is
helpful. The modest goal of this section is to explain some of the
object oriented principles to help you get up and running with the
Toolkit as soon as possible. Over time, you will gain OOP expertise
without even trying! If you are already familiar with OOP, skip to the
next section.
For now, we will concentrate on those aspects of OOP you will need in
order to understand how to use the Toolkit. In Part 2: Extending the
Toolkit, the more advanced concepts of inheritance and extensibility
are addressed.
In plain Pascal, there are types like integer, real, string, etc. and
you declare variables to be of a specific type. You can even define new
types. For example, the following declaration defines a new type
Address:
TYPE
Address = record
Name: string[20];
Street: string[30];
CityStZip: string[20];
end;
Having defined the type Address, you can then create variables of this
type, e.g.
VAR
BobsHouse: Address;
In most programs, you will write procedures and functions that can
manipulate the data stored in these variables, e.g.
procedure PrintLabel(Addr: address);
function Zip(Addr:address): string;
3-2 User's Guide
--------------------------------------------------------------------------------
But most of you know this stuff anyway. Things aren't so very different
with OOP. The primary difference is that, with OOP, the data and the
procedures and functions which manipulate the data are combined into a
single type, called an object. This concept of combining data and
procedures/functions is referred to as encapsulation. Listed below is a
way to create an object type called AddressOBJ:
TYPE
AddressOBJ = object
Name: string[20];
Street: string[30];
CityStZip: string[20];
{methods ...}
procedure PrintLabel;
function Zip: string;
end; {object}
VAR
BobsHouse: AddressOBJ;
Notice that the object type declaration is very similar to a record
declaration, but the keyword object is used instead of record. The
procedure and function declaration are included in the object declara-
tion, and are referred to (in OOP nomenclature) as methods. The methods
are not passed the address record as a parameter, because the procedure
and functions in an object can directly access the data in the object,
and so don't need to be passed the data. The "variable" BobsHouse,
which is of type AddressOBJ, is referred to as an instance - in other
words, object variables are called instances! All object type declara-
tions in the Toolkit end with the characters "OBJ".
The individual elements of an object (just like a record) can be
accessed by using the "dot" notation. For example, to print a label,
you would use the following statement:
BobsHouse.PrintLabel
You can also use the "with identifier do" shortcut, e.g.
with BobsHouse do
begin
PrintLabel
.....
end; {with}
In theory, you could also access the data elements using the dot
method, e.g. BobsHouse.Street := '12 Paradise Drive', but you
shouldn't! While it is syntactically correct and will compile, this is
bad practice. A basic precept of encapsulation is that you never access
Toolkit Basics 3-3
--------------------------------------------------------------------------------
the data elements of an instance directly. You should create methods
within the object to access the object's data. In the above example,
there is no way to access the data in the object (other than breaking
the rules) so a data update method would need to be created. Listed
below is an improved type declaration of the AddressOBJ:
TYPE
AddressOBJ = object
Name: string[20];
Street: string[30];
CityStZip: string[20];
{methods ...}
procedure Adddata(Nam,St,Ci,St,Zp:string);
procedure PrintLabel;
function Zip: string;
end; {object}
The new AddData method would be used to set the values of the Name,
Street and CityStZip elements. For example, the following two state-
ments would print the label:
with BobsHouse do
begin
AddData('Bobbo','12 Paradise Drive',
'Dome','TX','77186');
Printlabel;
end;
If you are curious, each method identified in an object must be
included in the body of the program or unit. For example, later in the
program there might be the following method definition:
...
procedure AddressOBJ.Adddata(Nam,St,Ci,St,Zp:string);
{}
begin
Name := copy(Nam,1,20);
Street := copy(St,1,30);
...
end; {of proc}
...
Now, back to the main discussion. The advantage of using methods to
access the object data is that the object user (that's you) does not
need to know or care about how the data is stored within the object.
The internal data structure might be modified at some stage to use
3-4 User's Guide
--------------------------------------------------------------------------------
pointers or to store ASCIIZ strings, etc, but the same method AddData
can still be called in the same way as previously. What Adddata does
(behind the scenes) may have changed, but your program still compiles
and runs without modification.
For various reasons, many objects need to be initialized before they
can be used. For example, some memory may need to be allocated on the
heap. When you have finished with such an object, the memory will need
to be disposed of. Just because the procedure in which you declared an
object instance (i.e. variable) has terminated, it does not necessarily
mean that the object data has been removed.
Although not mandatory, a de facto OOP standard is to have two special
methods for all objects. Namely, INIT and DONE. These special methods
are used to initialize an object and dispose of an object, respec-
tively. Throughout the Toolkit, every object has INIT and DONE methods.
Always call INIT before any other object methods, and always call DONE
when you have finished with an object. In some instances the INIT
method may require some parameters.
In our example, the object is useless if no data has been assigned.
Adopting the new convention, it might be more appropriate to rename the
AddData method INIT, since you will always want to assign values before
calling other object methods. We should also add a DONE method which
will provide a way of disposing of any dynamic data we might incorpo-
rate at a later stage. The revised object declaration would be as fol-
lows:
TYPE
AddressOBJ = object
Name: string[20]
Street: string[30]
CityStZip: string[20]
{methods ...}
procedure Init(Nam,St,Ci,St,Zp:string);
procedure PrintLabel;
function Zip: string;
procedure Done;
end; {object}
For now, the DONE procedure will probably be empty, i.e. it performs no
action. This is referred to as an abstract method. The following code
fragment shows how to use this revised object:
with BobsHouse do
begin
Init('Bobbo','12 Paradise Drive','Dome','TX','77186');
Printlabel;
Done;
end;
Toolkit Basics 3-5
--------------------------------------------------------------------------------
Note: there is an even more compelling reason to have INIT and DONE
methods. One of the most powerful features of OOP is polymorphism,
which allows you to declare virtual methods (discussed in part 2). In
general, objects which use virtual methods must have a constructor and
a destructor, and these are normally called INIT and DONE.
To recap, the following key points should be remembered:
q All Toolkit objects end with the characters OBJ.
q Use the "dot" notation to access object methods.
q When using the Toolkit always initialize an instance with INIT,
and dispose of it with DONE.
Having covered the OOP basics as they relate to the Toolkit, it is
worthwhile reviewing the message demo program that was discussed in
chapter 2:
program DemoMessage1;
{demms1}
Uses DOS, CRT,
totFAST, totMSG;
Var MsgWin : MessageOBJ;
begin
Screen.Clear(white,'░'); {paint the screen}
with MsgWin do
begin
Init(1,' Message ');
AddLine('');
AddLine('The message unit provides a');
AddLine('very easy way of displaying');
AddLine('pop-up messages in a move-');
AddLine('able window.');
AddLine('');
Show;
Done;
end;
end.
Hopefully, the statements make more sense now!
3-6 User's Guide
--------------------------------------------------------------------------------
"So what?" and "Why bother?" you may ask. It is not appropriate, at
this stage, to explore the advantages of encapsulation. Just use the
Toolkit a little, and you will see what can be done with OOP! We have
covered everything you need to know about OOP to use the Toolkit (and
then some), but as a programmer it is always good to explore "under the
hood". A great way to learn practical insights into OOP is to explore
the Toolkit source code. When you are ready to extend the Toolkit to
meet your specific needs, refer to Part 2. Also, read some of the OOP
literature in magazines and books - OOP is here to stay.
Meanwhile, be happy with the "how" for now. The "why" will become all
too clear in time.
Building the Toolkit TPUs
The file TOTBUILD.PAS is an "empty" file which USES all the Toolkit
units. Its sole purpose is to provide an easy way of re-compiling the
Toolkit units.
If you ever need to rebuild all the TPUs, load the TOTBUILD.PAS file
from the C:\TURBO\TOT directory (or wherever you installed the source
files), and select Compile Build. If the program does not successfully
compile, refer to the problems section at the end of chapter 2.
Compiler Directives
Every unit in the Toolkit has an include statement to include the file
TOTFLAGS.INC. This file is designed to specify all the common compiler
directives that you want to apply to every unit in your program.
The compiler directives added to your main program apply only to that
module and not to any of the units used by the program. So if you
wanted to ensure that a specific compiler directive is operative in
every unit, you would have to edit every unit source code file and add
the appropriate directive. (Yes, you could add them to the IDE options
menu, but if you work on multiple projects, you would have to keep
swapping the directives in and out as necessary.)
Whenever you develop a program using the Toolkit, you should add an
include directive to your main program and any other units you develop,
as follows:
{$I TOTFLAGS.INC}
Any compiler directives you set in the file TOTFLAGS.INC file will then
affect your code and the Toolkit code.
Toolkit Basics 3-7
--------------------------------------------------------------------------------
The TOTFLAGS.INC file contains a host of standard Turbo Pascal compiler
directives which are controlled with four special compiler directives:
FINAL, OVERLAY, FLOAT and FLOATEM. These four compiler directives are
located at the top of the file in an enabled or disabled state. For
example, in the disabled state the $DEFINE directive is broken up with
spaces, e.g.
{ $ DEFINE OVERLAY}
To activate a directive simply remove the leading spaces, e.g.
{$DEFINE OVERLAY}
To disable the directive again just put the spaces back!
The four compiler directives have a significant impact on the final
program code, and are discussed in detail below.
FINAL
During program development it is a good idea to switch on range check-
ing and stack checking, etc. These directives keep you honest and
reduce the likelihood of a machine "hang" or lock-up. For example, if
you try to assign a value of 300 to a byte, the compiler will identify
the problem before it goes too far. The bad news is that programs
compiled in the check everything state tend to be slower and larger
than their carefree brethren. So, once you have debugged and tested
your program and you are confident that the checking is no longer nec-
essary, you should switch off the appropriate directives.
The FINAL compiler directive is designed to simplify this task. During
program development, you should disable the FINAL compiler directive,
and then enable it when you are ready to build and distribute your
production program.
At the time of printing, the following compiler directives are
influenced by the FINAL directive:
FINAL enabled {$S-} no stack checking
{$R-} no range checking
{SD-} no debug information
{$L-} no local symbols
FINAL disabled {$S+} stack checking on
{$R+} range checking on
{SD+} debug information on
{$L+} local symbols on
3-8 User's Guide
--------------------------------------------------------------------------------
When FINAL is disabled, another Toolkit directive is defined: CHECK.
When CHECK is enabled, the Toolkit uses some additional code to check
parameters passed to methods. For example, in the WINOBJ method
SetSize, a check is made to ensure the window coordinates fit on the
screen. When the FINAL directive is enabled, CHECK is automatically
disabled to reduce program size. If a program runs fine until you set
the FINAL directive, check the parameters you are using in the problem
area of the code.
Remember that if you want to use the IDE or stand alone debugger on
your application, you must disable the FINAL directive.
OVERLAY
Any of the Toolkit units can be overlaid.
Turbo Pascal requires that all overlaid units include a {$O+} compiler
directive, and that all methods, procedures and functions use the far
call method, i.e. they are compiled in the {$F+} state. By activating
the {$DEFINE OVERLAY} statement in the TOTFLAGS.INC file, all the Tool-
kit units will be compiled in the {$F+,O+} state.
It is important to note that Turbo Pascal imposes an important restric-
tion on an overlaid unit - there must be no initialization statements
at the end of the unit. Every Toolkit unit has an initialization
procedure, and this procedure name is consistently the unit name minus
the TOT prefix plus the characters "INIT". For example, the initializa-
tion procedures for the TOTFAST and TOTSYS units are FASTINIT and SYSI-
NIT, respectively.
IMPORTANT: When the OVERLAY compiler directive is activated, you must
call each overlay unit's INIT procedure as the first statements in your
main program.
Listed below is a small demo program, DEMOV1.PAS, which is an overlaid
version of the DEMMS1.PAS file reviewed earlier.
program DemoOverlay1;
{demov1.pas - make sure the OVERLAY compiler directive
is enabled in the TOTFLAGS.INC file before compiling}
{$I TOTFLAGS.INC}
Uses OVERLAY, DOS, CRT,
totSYS, totLOOK, totINPUT, totFAST, totWIN, totIO1, totMSG;
{$O totSYS}
{$O TOTLOOK}
{$O totINPUT}
{$O totFAST}
Toolkit Basics 3-9
--------------------------------------------------------------------------------
{$O totWIN}
{$O totIO1}
{$O totMSG}
Var
MsgWin : MessageOBJ;
begin
OvrInit('DEMOV1.OVR');{initialize the overlay}
OvrInitEMS;
SYSInit; {initialize the Toolkit units}
LOOKInit;
INPUTInit;
FASTInit;
WINInit;
IO1Init;
MSGInit;
Screen.Clear(white,'░'); {paint the screen}
with MsgWin do
begin
Init(1,' Message ');
AddLine('');
AddLine('The message unit provides a');
AddLine('very easy way of displaying');
AddLine('pop-up messages in a move-');
AddLine('able window.');
AddLine('');
Show;
Done;
end;
end.
Note that all the units used directly or indirectly by the totMSG unit
are used and the appropriate INIT procedure is called. The order of the
INIT procedure calls is important. If you are using any Toolkit units
which write to the screen and poll the keyboard, then you should, as a
minimum, call the following procedures in the specified order:
SYSInit;
LOOKInit;
INPUTInit;
FASTInit;
WINInit;
If you execute the DEMOV1 program you will notice it is unbearably
slow! As the demo ably illustrates, you should not overlay the primary
Toolkit units totSYS, totINPUT, and totFAST. Routines from these units
are called very frequently, and placing them in overlays will really
slooooow your application down. DEMOV2.PAS, listed below, is a more
practical overlay solution:
3-10 User's Guide
--------------------------------------------------------------------------------
program DemoOverlay2;
{demov2 - make sure the OVERLAY compiler directive
is enabled in the TOTFLAGS.INC file before compiling}
{$I TOTFLAGS.INC}
Uses OVERLAY, DOS, CRT,
totSYS, totLOOK, totINPUT, totFAST, totWIN, totIO1, totMSG;
{$O totWIN}
{$O totIO1}
{$O totMSG}
Var
MsgWin : MessageOBJ;
begin
OvrInit('DEMOV2.OVR');{initialize the overlay}
OvrInitEMS;
SYSInit; {initialize the Toolkit units}
LOOKInit;
INPUTInit;
FASTInit;
WINInit;
IO1Init;
MSGInit;
Screen.Clear(white,'░'); {paint the screen}
with MsgWin do
begin
Init(1,' Message ');
AddLine('');
AddLine('The message unit provides a');
AddLine('very easy way of displaying');
AddLine('pop-up messages in a move-');
AddLine('able window.');
AddLine('');
Show;
Done;
end;
end.
In this example, only the three units totWIN, totIO1 and totMSG are
overlaid, and performance is almost as good as a non-overlaid version.
It is important to note the OVERLAY compiler directive disables all the
Toolkit initialization procedures regardless of whether each unit is
actually overlaid or not. For this reason, the second demo still ini-
tializes all of the Toolkit units. Refer to the Flash cards for a list
of unit dependencies, i.e. which files to INIT when you use a unit.
Toolkit Basics 3-11
--------------------------------------------------------------------------------
Finally, if you are new to overlays, don't forget that the overlay file
(.OVR) can be combined back into the EXE file using the following DOS
command:
COPY/B progname.EXE + progname.OVR
The OvrInit procedure must initialize the overlay file from the EXE
file, and this can be achieved with the following command:
OvrInit(ParamStr(0));
FLOAT
Turbo Pascal and the Toolkit support extended reals. By default, Turbo
Pascal uses six byte reals, but using compiler directives high preci-
sion Single, Double, Extended and Comp reals can be used.
If you want to use the higher precision reals, activate the FLOAT com-
piler directive. The Toolkit will automatically set the necessary Turbo
Pascal compiler directives. When FLOAT is enabled, the Toolkit supports
all real types. When FLOAT is disabled, all the real types are type-
cast to the base REAL type. In other words, the types SINGLE, DOUBLE,
EXTENDED and COMP appear to the compiler as plain old REAL. This
type-casting is performed in the small totREAL unit.
If the software compiled in the FLOAT state is to be run on a computer
without a math co-processor, the FLOATEM compiler directive (discussed
next) must also be enabled. Note that the totSYS unit provides an
object for checking the presence of a math co-processor.
FLOATEM
Turbo Pascal is capable of emulating an 8087 math co-processor if the
PC does not have one installed. Enable the FLOAT and FLOATEM (short for
float emulation) directives if you want to use high precision reals on
PCs with no math co-processor.
Note that the use of FLOATEM will increase the size of the program,
because Turbo Pascal links in the 8087 emulation code. Only use this
directive when necessary.
Using Standard Objects
Virtually all programs built with the Toolkit perform some basic tasks
such as writing to the screen and polling the keyboard. The Toolkit
provides a number of object instances (i.e. object variables) that are
automatically initialized when you use the related unit. For example,
the totFAST unit includes an instance of a ScreenOBJ called SCREEN.
3-12 User's Guide
--------------------------------------------------------------------------------
Listed below are each of the instances which provide the basic program-
ming facilities:
SCREEN The SCREEN instance is of type ScreenOBJ and is
declared in the totFAST unit. SCREEN should be used
for all writing to the screen. For more details, refer
to chapter 5: Writing to the Screen.
MOUSE The MOUSE instance is of type MouseOBJ and is declared
in the totINPUT unit. The primary purpose of MOUSE is
to provide a convenient way of controlling the mouse
cursor. The methods HIDE and SHOW control whether the
mouse is visible, and the method function VISIBLE
returns true if the mouse is on display. Note that the
Toolkit automatically hides the mouse while screen
writing occurs. For further information, refer to
chapter 6: Keyboard and Mouse Input.
KEY The KEY instance is of type KeyOBJ and is also
declared in the totINPUT unit. This instance provides
all the methods for accessing the user's keyboard and
mouse input. The main method is Getkey, which waits
for the user to press a key or click a mouse button.
More details are described in chapter 6.
MONITOR^ The MONITOR instance is a pointer to a DisplayOBJ and
is declared in the totSYS unit. MONITOR^ can be used
to ascertain the width and depth of the display, as
well as set condensed mode display on or off. Refer to
chapter 4: Determining and Controlling Hardware for
more information.
Controlling a Program's Look & Feel
As well as the global instances described in the last section, the
Toolkit includes a variety of object instances which can be used to
control the overall look and feel of a program. For example, the
SCROLLTOT^ instance controls the way that scroll bars are drawn.
To change the look of your application, all you have to do is modify
the appropriate instance. To save data space, all these instances are
dynamically created on the heap and must be referenced with the pointer
symbol (^). For example, to call the SCROLLTOT method SetScrollChars,
you would use the following syntax:
ScrollTOT^.SetScrollChars(....);
Toolkit Basics 3-13
--------------------------------------------------------------------------------
Listed below is a full description of each global instance which con-
trols the look and feel of your application. All these instances are
automatically initialized by the Toolkit, and a set of more than
adequate defaults (!) are assigned.
In addition to these instances, there is a byte variable LPTPORT, in
the totMISC unit, which is used to indicate the default printer port
(set to 0 for LPT1, 1 for LPT2, etc.).
Note: the Toolkit uses a single byte to indicate the display
attribute or color - that is, the foreground and background bytes
combined into a single attribute byte. The totFAST unit provides
three functions to help you manipulate color attributes. The CATTR
function is passed a foreground and background color and returns a
single combined attribute byte. The FATTR function is passed an
attribute byte and returns the foreground color component. The
BATTR function is passed an attribute byte and returns the back-
ground color component.
For example, the expression CAttr(white,blue); returns the value of
31, and the expression FAttr(31) returns 15, which is white.
In all, there are 256 different foreground and background color
combinations; the Flash Cards include a chart which details them
all.
When assigning colors, be sure to check the Monitor^.ColorOn bool-
ean function method to determine whether the system is using a
color or a monochrome device.
LookTOT
The unit totLOOK is designed specifically to provide you with an easy
way to change the overall cosmetic appearance of your programs. The
unit includes a single instance LookTOT which is a pointer to a LookOBJ
object. LookTOT controls the window, menu and list default display
characteristics. If you want to change the overall color and style of
your program, change the LookTOT settings, and these will be inherited
by the window, menu and list objects.
Listed below are the methods for setting the various defaults:
SetWindow(Border,Body,Icons,Title: byte);
3-14 User's Guide
--------------------------------------------------------------------------------
This method sets the display attributes for the window border (where
the box is drawn), the central part of the window, the close and zoom
characters, and the window title. The defaults depend on whether the
host PC is using a color or a monchrome display.
SetWinKeys(Move,Stretch,Zoom: word);
This method sets the values of the keys which will invoke the window
move, stretch and zoom commands. The defaults are [KEYCAP], [KEYCAP],
and [KEYCAP].
SetListKeys(Endkey,Esc,Toggle,Tag,UnTag: word);
SetListKeys sets the values of the keys which are used with a ListOBJ
instance. The EndKey and Esc keys are used to remove the list window,
and the defaults are [KEYCAP] and [KEYCAP]. The Toggle key is used to
select or deselect individual items in the list and the default is the
[KEYCAP]. The Tag and UnTag keys are used to globally select or dese-
lect all items in the list, and the defaults are [KEYCAP] and [KEYCAP].
SetListChars(LeftChar,RightChar,ToggleOnChar,ToggleOffChar:char);
Sets the display characters which are used to emphasize the highlighted
topic in a list, as well as the characters used to indicate whether an
item in a list is selected or not.
SetMenu(Bor,Tit,Icon,HiHot,HiNorm,LoHot,LoNorm,Off:byte)
Sets the display characteristics of the pop-up and pull-down menus. The
method is passed eight (count 'em) parameters to give you complete
control of all the menu display colors. The first three parameters set
the attribute of the menu window border, title and close icon. The next
four parameters specify the attributes for the highlighted and normal
menu items. (Each menu item may be displayed in two colors to emphasize
a specific letter or word.) The last parameter is the attribute for
non-selectable (i.e. turned-off) menu items.
SetDefaults;
Call this method with no parameters if you want to reset all the Look-
TOT settings to the Toolkit defaults.
Toolkit Basics 3-15
--------------------------------------------------------------------------------
ShadowTOT
ShadowTOT is a pointer to an instance of type ShadowOBJ, and is
declared in the totFAST unit. ShadowTOT is used to control the size,
color and perspective of the shadows used by pop-up windows, lists,
menus and the like.
An enumerated type ShadowPosition is used to describe the shadow per-
spective, and the elements are defined as UpLeft, UpRight, DownLeft,
and DownRight. Shadows can be set as see-through or solid characters,
the choice is yours! You can even set how wide and deep the shadow will
be.
The following methods are used to set the shadow characteristics:
SetShadowStyle(ShadP:ShadowPosition;ShadA:byte;ShadC:char);
The first parameter indicates the direction of the shadow using a mem-
ber of the ShadowPosition enumerated type. The second parameter is the
display attribute of the shadow, and the third is the character used to
draw the shadow. If a space (' ') is passed, the shadow will be see-
through, otherwise the shadow will be drawn using the specified charac-
ter.
SetShadowSize(ShadW,ShadD:byte);
This method controls the size of the shadow. Pass the number of charac-
ters wide and deep that you want the shadow to be. If the width and
depth are set to zero, no shadows will be drawn.
SetDefaults;
Call this method with no parameters if you want to reset all the Shad-
owTOT settings to the Toolkit defaults.
The following program, DEMSH1.PAS, illustrates how to change the shadow
settings, and figure 3.1 shows the resultant output when the program is
executed.
program DemoShadow1;
{demsh1}
Uses DOS, CRT,
totFAST;
begin
with Screen do
begin
Clear(white,'░'); {paint the screen}
ShadFillBox(3,3,20,8,31,1);
ShadowTOT^.SetShadowStyle(Upleft,lightgray,' ');
3-16 User's Guide
--------------------------------------------------------------------------------
ShadFillBox(3,12,20,19,47,2);
ShadowTOT^.SetShadowStyle(Downleft,lightblue,' ');
ShadowTOT^.SetShadowSize(4,1);
ShadFillBox(35,2,70,10,94,3);
ShadowTOT^.SetShadowStyle(DownLeft,white,'!');
ShadFillBox(40,13,60,18,15,4);
ShadowTOT^.SetDefaults;
ShadFillBox(5,21,75,23,78,5);
end; {with}
end.
Figure 3.1 [SCREEN]
The Shadow Demo
Program
ScrollTOT
ScrollTOT is a pointer to an instance of type ScrollOBJ, and is
declared in the totFAST unit. ScrollTOT is used to control the charac-
ters used to build the scroll bars displayed in scrolling windows.
There are basically four different characters used to create a scroll
bar. There is the directional arrow at each end, the background charac-
ter, and the elevator (or slider) character. These characters are con-
trolled with the following two methods:
SetScrollChars(U,D,L,R,E,B:char);
These six parameters represent the up and down directional arrows on
vertical scroll bars, the left and right directional arrows on horizon-
tal scroll bars, the elevator character and the background character.
SetDefaults;
Call this method with no parameters if you want to reset all the
ScrollTOT settings to the Toolkit defaults.
ScrollTOT does not affect the display attributes of the scroll bars.
The window border attribute is normally used.
SCREEN provides two methods for writing scroll bars anywhere on the
display: WriteHScrollBar, WriteVScrollBar. Refer to Chapter 5 for fur-
ther information.
Toolkit Basics 3-17
--------------------------------------------------------------------------------
IOTOT
Using consistent color schemes is particularly important during full-
screen input. The totIO1 unit includes IOTOT which is designed to con-
trol all the IO display attributes. IOTOT is a pointer to an object of
type InputOBJ. The uses of IOTOT are discussed in detail in chapter 11.
FmtNumberTOT
The totIO2 unit provides routines for the input of REAL and INTEGER
values. These values can be optionally formatted when the user moves to
the next field, i.e. when the user is editing, the number is unfor-
matted, but when the user exits the field, the number can be formatted
in a variety of styles. For example, the number 123456.78 might be
formatted as $123,456.78.
The totIO2 unit includes FmtNumberTOT, a pointer to an object instance
of type FmtNumberOBJ. This instance defines the default formatting that
will be applied to real and integer fields during full-screen input.
Any of the format defaults can be overridden for individual fields.
Field formatting is discussed in detail in chapter 11: Controlling User
Input.
DateTOT
The totDATE unit provides functions for manipulating and converting
Julian and Gregorian dates. A number of default values, e.g. the char-
acter used to separate the month from the day and the year (like ' /
/ '), are defined in DateTOT, a pointer to an object instance of type
DateOBJ. These defaults are used in both the totDATE and totIO2 units.
Refer to chapter 13: Managing Dates for further details.
AlphabetTOT
The totINPUT unit includes the object AlphabetOBJ for managing upper-
and lower-case characters, and the global instance AlphabetTOT is a
pointer to an AlphabetOBJ object.
AlphabetTOT controls how the Toolkit determines/changes the case of
alpha-characters. It is designed for international Toolkit users who
want to use a non-English alphabet. If you are writing "English-
speaking" programs, you do not need to tamper with this object.
The object contains a list of all valid upper-case letters, lower-case
letters and punctuation characters. The totLOOK unit includes the type
declaration CharSet, which is equal to a set of char. Some methods are
3-18 User's Guide
--------------------------------------------------------------------------------
passed a parameter of type CharSet. You may specify multiple characters
and/or ranges of characters, provided that they are enclosed in square
brackets []. For example, the following expressions are valid CharSets:
['a','b','f'..'z']
['A'..'Z',#129..#148]
['a'..'z']
[',','.']
AlphabetTOT methods can be called using the syntax AlphabetTOT^.method,
and the following methods are supported:
SetUpper(Letters:CharSet);
Defines which characters comprise the upper-case alphabet. The method
is passed one parameter of type CharSet, e.g. SetUpper(['A'..'Z']);.
SetLower(Letters:CharSet);
Defines which characters comprise the lower-case alphabet. The method
is passed one parameter of type CharSet, e.g. SetLower(['a'..'z']);.
SetPunctuation(Letters:CharSet);
Defines which characters are used in normal punctuation. The method is
passed one parameter of type CharSet, e.g. SetPunctua-
tion([',',';','.',':',' ']);.
IsUpper(K:word): boolean;
This function method is passed one parameter, representing the ordinal
value of a character, and returns true if the character is listed in
the upper-case alphabet, e.g. IsUpper(ord('A'));.
IsLower(K:word): boolean;
This function method is passed one parameter, representing the ordinal
value of a character, and returns true if the character is listed in
the lower-case alphabet, e.g. IsLower(107);.
IsLetter(K:word): boolean;
This function method is passed one parameter, representing the ordinal
value of a character, and returns true if the character is listed in
either the upper- or lower-case alphabet.
IsPunctuation(K:word): boolean;
Toolkit Basics 3-19
--------------------------------------------------------------------------------
This function method is passed one parameter, representing the ordinal
value of a character, and returns true if the character is listed as a
punctuation character.
On occasion, the Toolkit needs to convert the case of alpha characters.
To accommodate international users, the Toolkit uses AlphabetTOT to
convert character case, rather than rely on the English-specific rou-
tines provided with Turbo Pascal. The Toolkit calls the following two
methods to convert character case:
GetUpCase(Ch:char):char;
This method is passed a character, and returns the upper-case equiva-
lent of the character.
GetLoCase(Ch:char):char;
This method is passed a character, and returns the lower-case equiva-
lent of the character.
You can control precisely how characters are converted by creating your
own conversion routines. All you have to do is create two functions
following some specific rules, and then call the methods Alphabet-
TOT^.AssignUpCaseFunc and AlphabetTOT^.AssignLoCaseFunc to instruct the
Toolkit to use your functions.
For a function to be eligible as a character case converter it must
adhere to the following three rules:
Rule 1 The function must be declared as a FAR function. This can be
achieved by preceding the function with a {$F+} compiler
directive, and following the function with a {$F-} direc-
tive. Alternatively, Turbo 6 users can use the new keyword
FAR following the procedure statement.
Rule 2 The function must be declared with one passed parameter of
type char, and it must return a char.
Rule 3 The function must be at the root level, i.e. the function
cannot be nested within another procedure or function.
The following function declaration follows these rules:
{$F+}
function MyUpConverter(Ch:char):char;
.....{statements}
end;
{$F-}
3-20 User's Guide
--------------------------------------------------------------------------------
Internally, these functions should check the value of the passed char-
acter, and return the character converted to the appropriate case. If
the character is not suited to conversion, e.g. '1', simply return the
character that was passed. Once you have created two functions (one for
upper-case conversion and one for lower-case conversion), you should
call the following assignment methods to instruct AlphabetTOT to use
your routines:
AssignUpCaseFunc(Func:CaseFunc);
This method is passed the name of the function used to convert charac-
ters to upper case. The procedure must adhere to the rules outlined
above.
AssignLoCaseFunc(Func:CaseFunc);
This method is passed the name of the function used to convert charac-
ters to lower case. The procedure must adhere to the rules outlined
above.
In summary, AlphabetTOT provides you with complete control over how the
Toolkit determines and changes the case of alpha characters.
Program Size
A constant battle during the development of the Toolkit was to minimize
the size of programs developed with the Toolkit. A valid criticism of
OOP is that it tends to swell the final program size, which makes it a
subject of concern to most developers (that's you folks).
With a hierarchical object organization even small applications tend to
attract a high code overhead. However, the more features of the Toolkit
you use, the more efficient your program will be. For example, listed
below are the EXE file sizes of three of the demo programs:
DemFM8 114k
DemDR1 92k
DemMS1 56k
The combined file size of the three programs is 262k. However, if these
three examples are combined into a single example, the file size is
actually 141k. The reason for the reduction is that each of the small
programs uses common routines which can be shared in the combined
program.
Toolkit Basics 3-21
--------------------------------------------------------------------------------
In real life, your fledgling program will start out bigger than you
expected, but it will grow much less than anticipated as your program
expands. Remember that compiler directives have a significant impact on
program size, and you should enable the FINAL compiler directive for
the production build of your application.
If EXE file size is your concern, rather than code size, consider com-
pressing the EXE file with a compression utility like PKlite from
PKWare, Inc., or LZEXE by Fabrice Bellard.